import { Meta } from '@storybook/blocks';

<Meta title="Frameworks/React" />

# Using Baklava in React

React is not [compatible](https://custom-elements-everywhere.com/#react) with most of the web component features. React passes all props as string to Custom Components so object and array props don't pass in correct way. Also, since React uses its own synthetic event system, it can't listen events that dispatches from Custom Elements. For this reasons, we used [@lit-labs/react](https://www.npmjs.com/package/@lit-labs/react) package to convert Custom Elements to React components.

## Using with CDN

Install the NPM package to your project.

```bash
npm install @trendyol/baklava
```

Include Baklava library from CDN to your project's `index.html` file's `<head>` section.

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@trendyol/baklava/dist/themes/default.css"/>
<script type="module" src="https://cdn.jsdelivr.net/npm/@trendyol/baklava/dist/baklava.js"></script>
```

Then you can use Baklava React components in your project by importing them from `@trendyol/baklava/dist/baklava-react` in your code.

<bl-alert variant="warning" icon>
  Please make sure you are using same version on CDN imports and NPM package. Otherwise there can be inconsistencies between React components and their related web components.
</bl-alert>

```jsx
import { BlTooltip, BlButton } from "@trendyol/baklava/dist/baklava-react";

function App() {
  return (
    <BlTooltip>
      <BlButton slot="tooltip-trigger" icon="info" label="Show Info" />
      Some extra information.
    </BlTooltip>
  );
}

export default App;
```

By using via CDN, you'll have a very thin React wrapper package in your project bundle, and you'll be able to use Baklava React components in your project with a very fast and optimized CDN. In this way you don't need to do any special thing for including assets.

## Using with NPM

If you want to include Baklava to your project bundle, you can import it via NPM.

Install the NPM package to your project.

```bash
npm install @trendyol/baklava
```

Then import Baklava library and styles in a central place of your app. Like `main.jsx` file. You need to use provided `setIconPath` function to set icon location via CDN. Or you can download those icons to your project's asset folder and set the path manually.

```jsx
import React from "react";
import ReactDOM from "react-dom/client";
import "@trendyol/baklava";
import { setIconPath } from "@trendyol/baklava";
import "@trendyol/baklava/dist/themes/default.css";
setIconPath("https://cdn.jsdelivr.net/npm/@trendyol/baklava-icons@latest/icons");

import App from "./App";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
```

Now you are able to use Baklava React components in your project by importing them from `@trendyol/baklava/dist/baklava-react` in your code.

```jsx
import { BlTooltip, BlButton } from "@trendyol/baklava/dist/baklava-react";

function App() {
  return (
    <BlTooltip>
      <BlButton slot="tooltip-trigger" icon="info" text label="Show Info" />
      Some extra information.
    </BlTooltip>
  );
}

export default App;
```

## Event Handling

Baklava components emit [custom events](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). For example, the input component emits the `bl-input` event when it receives input. In React, you can listen for the event using `onInput`.

Example:

```jsx
import { useState } from 'react';
import { BlInput } from '@trendyol/baklava/dist/baklava-react';

function MyComponent() {
  const [value, setValue] = useState('');

  return <BlInput value={value} onInput={event => setValue(event.target.value)} />;
}

export default MyComponent;
```

## Styling Components
You can customize components with css variables or general theme variables.

#### Inline CSS

```jsx
import { BlButton } from "@trendyol/baklava/dist/baklava-react";

function MyComponent() {
  const buttonStyle = {
    "--bl-color-primary": "purple",
    "--bl-color-primary-highlight": "rebeccapurple",
  }

  return (
    <BlButton style={buttonStyle}>button</BlButton>
  );
}

export default MyComponent;
```

#### Styled Components

```jsx
import { BlTooltip, BlButton } from "@trendyol/baklava/dist/baklava-react";
import styled from "styled-components"

const Wrapper = styled.div`
   .button-class {
     --bl-color-primary: purple;
   }

   .tooltip-class {
     --bl-tooltip-position: fixed;
   }
`;

function MyComponent() {
  return (
    <Wrapper>
      <BlTooltip className="tooltip-class">
        <BlButton className="button-class" slot="tooltip-trigger" icon="info" text label="Show Info" />
        Some extra information.
      </BlTooltip>
    </Wrapper>
  );
}

export default MyComponent;
```

## Testing with Vitest

Baklava uses ES modules. We will explain how to install Vitest due to its ES Modules support. If you are using Jest,
your version should be greater than 26.5.0, and you should add "@trendyol/baklava" to the
[transformIgnorePatterns](https://jestjs.io/docs/tutorial-react-native#transformignorepatterns-customization).

```shell
npm install -D vitest vitest-dom jsdom
```

After downloading Vitest with this command, you should provide a file path to the setupFiles section in your
Vitest config file. We used './src/setupTest.ts'.

```js
import {defineConfig} from "vitest/config";

export default defineConfig({
  test: {
    ...otherProps,
    environment: "jsdom",
    setupFiles: ["./src/setupTest.ts"]
  }
});
```

Afterward, we should edit our setupTest.ts file just like setting up baklava.

```js
import "vitest-dom/extend-expect";
import "@trendyol/baklava";
import { setIconPath } from "@trendyol/baklava";
import "@trendyol/baklava/dist/themes/default.css";
setIconPath("https://cdn.jsdelivr.net/npm/@trendyol/baklava-icons@latest/icons");
```

We are ready to write tests.

```tsx
import { fireEvent, render, screen } from "@testing-library/react";
import { expect, test, vi } from "vitest";
import { BlButton } from "@trendyol/baklava/dist/baklava-react";
import React from "react";

test("should trigger click event", async () => {
  const onClickFn = vi.fn();
  render(
    <React.Suspense fallback={null}>
      <BlButton onBlClick={onClickFn}>Button</BlButton>
    </React.Suspense>
  );

  const blButton = await screen.findByText("Button");
  const button = blButton.shadowRoot!.querySelector("button")!;
  fireEvent.click(button);

  expect(onClickFn).toBeCalled();
});
```
